/** @author temujin Mar 20, 2012 */
package paim.wingchun.view;

import java.lang.reflect.MalformedParametersException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.EventListener;

import javax.swing.event.EventListenerList;

import paim.wingchun.controller.WC_Event;

/** @author temujin Mar 20, 2012 */
public interface Fireable<L extends EventListener> {

    /* Create the listener list */
    // default EventListenerList listenerList = new EventListenerList();

    public EventListenerList getListenersList();

    /* usar quando tiver java8 como interface funcional public default EventListenerList getListeners() { return listenerList; } */

    /** This private class is used to fire WCEvent */
    public void fire(WC_Event e);

    public default L[] fireListeners() {
        L[] listeners = getListenersList().getListeners(getEventListener(this.getClass()));
        return listeners;
    }

    /** This methods allows classes to register for WCEvent */
    public default void addListener(L listener) {
        getListenersList().add(getEventListener(this.getClass()), listener);
    }

    /** This methods allows classes to unregister for WCEvent */
    public default void removeListener(L listener) {
        getListenersList().remove(getEventListener(this.getClass()), listener);
    }

    public static <EL extends EventListener> Class<EL> getEventListener(final Class<?> parameterizedClass) {

        Type[] interfaces = parameterizedClass.getGenericInterfaces();

        for ( Type inter : interfaces ) {
            if ( !ParameterizedType.class.isAssignableFrom(inter.getClass()) )
                continue;

            ParameterizedType interfaceParametrizada = (ParameterizedType) inter;
            Type rawType = interfaceParametrizada.getRawType();

            if ( !Fireable.class.isAssignableFrom((Class<?>) rawType) )
                continue;

            Type[] parametros = interfaceParametrizada.getActualTypeArguments();

            for ( Type par : parametros ) {
                if ( EventListener.class.isAssignableFrom((Class<?>) par) )
                    return (Class<EL>) par;
            }
        }

        /* se nao encontrou, tenta na super */
        Class<?> superClass = parameterizedClass.getSuperclass();
        if ( superClass.getSimpleName().equals(Object.class.getSimpleName()) )
            throw new MalformedParametersException();

        return getEventListener(superClass);

    }

}
